<template>
  <div class="virtual-scroll-grid" :style="{ height: getHeight }">
    <!-- 左列虚拟列表 -->
    <div class="scroller-left" v-loading="loading">
      <recycle-scroller
        :key-field="keyField"
        :items="getItemsList"
        :item-size="itemSize"
        @scroll-end="onScrollEnd"
      >
        <template #default="{ item }">
          <div class="scroller-grid" :style="{ height: `${itemSize}px` }">
            <div
              class="scroller-grid-item"
              :style="{ width: `calc(100% / ${rowCount})` }"
              v-for="gridItem in item.child"
              :key="gridItem"
            >
              <div class="scroller-grid-content" @click.stop="onItemChange(gridItem)">
                <el-checkbox
                  @click.stop
                  class="scroller-grid-checkbox"
                  :model-value="checkItemsMap[gridItem[keyField]]"
                  @change="onItemChange(gridItem)"
                ></el-checkbox>

                <div class="scroller-image" v-if="imageType == 5">
                  <img
                    v-for="(item, index) in gridItem.images"
                    :key="item"
                    class="scroller-image-item"
                    :src="item.url"
                  />
                </div>

                <img v-else class="scroller-grid-img" :src="gridItem.images[0].url" alt="" />
              </div>
            </div>
          </div>
        </template>
      </recycle-scroller>
    </div>

    <!-- 右列虚拟列表 -->
    <div class="scroller-right">
      <div class="is-title scroller-title">
        已选：
        <span>{{ cacheCheckItems.length }}</span>
      </div>
      <recycle-scroller :key-field="keyField" :items="getCacheCheckItems" :item-size="itemSize">
        <template #default="{ item }">
          <div class="scroller-grid" :style="{ height: `${itemSize}px` }">
            <div
              class="scroller-grid-item"
              :style="{ width: `calc(100% / ${rowCount})` }"
              v-for="gridItem in item.child"
              :key="gridItem"
            >
              <div class="scroller-grid-content">
                <div class="scroller-image" v-if="imageType == 5">
                  <img
                    v-for="(item, index) in gridItem.images"
                    :key="item"
                    class="scroller-image-item"
                    :src="item.url"
                  />
                </div>
                <img v-else class="scroller-grid-img" :src="gridItem.images[0].url" alt="" />
                <el-icon :size="12" class="scroller-grid-close" @click="onItemClose(gridItem)">
                  <CloseBold />
                </el-icon>
              </div>
            </div>
          </div>
        </template>
      </recycle-scroller>
    </div>
  </div>
</template>

<script setup name="virtual-scroll-grid">
import { computed, nextTick, ref, watchEffect } from 'vue';
import { CloseBold } from '@element-plus/icons-vue';
import { RecycleScroller } from 'vue-virtual-scroller';
import 'vue-virtual-scroller/dist/vue-virtual-scroller.css';
import { setChildDimArray } from '@/utils/tools';

const emit = defineEmits(['update:checkItems', 'on-scroll-end']);

const props = defineProps({
  // 待选择数据
  items: {
    type: Array,
    default: () => [],
  },

  // id字段名
  keyField: {
    type: String,
    default: 'id',
  },

  // 每一项高度大小
  itemSize: {
    type: Number,
    default: 50,
  },

  // 整体高度
  height: {
    type: [Number, String],
    default: 520,
  },

  // 已选中数据
  checkItems: {
    type: Array,
    default: () => [],
  },

  // 横向数量
  rowCount: {
    type: Number,
    default: 5,
  },

  // loading
  loading: {
    type: Boolean,
    default: false,
  },

  aspectRatio: {
    type: String,
    default: '9/16',
  },

  imageType: {
    type: [String, Number],
    default: '',
  },
});

const getHeight = computed(() =>
  typeof props.height == 'string' ? props.height : `${props.height}px`,
);

const getItemsList = computed(() => setChildDimArray(props.items, props.rowCount, props.keyField));

const getCacheCheckItems = computed(() =>
  setChildDimArray(cacheCheckItems.value, props.rowCount, props.keyField),
);

// 是否全选
const isAllChecked = computed(() => cacheCheckItems.value.length === props.items.length);

// 部分数据勾选状态
const isIndeterminate = computed(() =>
  isAllChecked.value ? false : cacheCheckItems.value.length > 0,
);

// 是否选择字典
const checkItemsMap = ref({});

// 已选择暂存数据
const cacheCheckItems = ref(props.checkItems);

// 是否执行watchEffect里的计算
let isEffect = true;

console.log('virtual-scroll-grid');

watchEffect(() => {
  if (isEffect) {
    console.log('checkItems更新', props.checkItems);
    console.log('items更新');

    cacheCheckItems.value = props.checkItems;

    for (const item of props.items) {
      checkItemsMap.value[item[props.keyField]] = false;
    }

    for (const item of props.checkItems) {
      checkItemsMap.value[item[props.keyField]] = true;
    }
  }
});

const onItemChange = (item) => {
  let status = checkItemsMap.value[item[props.keyField]];

  checkItemsMap.value[item[props.keyField]] = !status;

  let index = cacheCheckItems.value.findIndex((v) => v[props.keyField] == item[props.keyField]);

  if (index === -1) {
    cacheCheckItems.value = cacheCheckItems.value.concat([item]);
  } else {
    cacheCheckItems.value.splice(index, 1);
    cacheCheckItems.value = cacheCheckItems.value.concat([]);
  }

  updateCheckItems();
};

const onAllChange = () => {
  for (const item of props.items) {
    checkItemsMap.value[item[props.keyField]] = !isAllChecked.value;
  }
  cacheCheckItems.value = !isAllChecked.value ? props.items.concat([]) : [];
  updateCheckItems();
};

const onItemClose = (item) => {
  onItemChange(item);
};

const updateCheckItems = () => {
  isEffect = false;
  emit('update:checkItems', cacheCheckItems.value);
  nextTick(() => (isEffect = true));
};

const onScrollEnd = () => {
  console.log('底部');
  emit('on-scroll-end');
};
</script>

<style lang="scss" scoped>
@mixin item() {
  display: flex;
  align-items: center;
  padding: 0 12px;
  box-sizing: border-box;
}

.virtual-scroll-grid {
  width: 100%;
  display: flex;
  border: 1px solid var(--el-border-color);
  padding: 18px 0;
  box-sizing: border-box;
  border-radius: 4px;
}

.scroller-left,
.scroller-right {
  display: flex;
  flex-direction: column;
  width: 100%;
  height: 100%;
  padding: 0 6px;
  min-width: 220px;
}

.scroller-left .is-checked.scroller-left-item {
  background-color: var(--el-color-info-light-8);
  border-radius: 4px;
}

.scroller-right {
  border-left: 1px dashed var(--el-border-color);
  box-sizing: border-box;
}

.scroller-left-item,
.scroller-right-item {
  width: 100%;
  @include item();

  &:hover {
    background-color: var(--el-color-info-light-8);
    border-radius: 6px;
  }
}

.scroller-right-item {
  justify-content: space-between;

  &--left {
    flex: 1;
  }

  &--close {
    cursor: pointer;
    font-size: 14px;
  }
}

.scroller-all,
.scroller-select {
  height: 30px;
  flex-shrink: 0;
  @include item();
}

.scroller-grid {
  display: flex;
  align-items: center;
}

.scroller-grid-item {
  height: 100%;
  padding: 6px 6px;
  position: relative;
  box-sizing: border-box;
  display: flex;
  align-items: center;
  justify-content: center;
}

.scroller-grid-content {
  // width: 100%;
  height: 100%;
  aspect-ratio: 1/1;
  // background-color: #eee;
  border: 1px solid #e6e6e6;
  border-radius: 6px;
  position: relative;
  overflow: hidden;
}

.scroller-grid-img {
  width: 100%;
  height: 100%;
  object-fit: contain;
}

.scroller-image {
  width: 100%;
  height: 100%;
  display: flex;
  flex-wrap: wrap;
  padding: 5px;
  box-sizing: border-box;
}

.scroller-image-item {
  width: calc(100% / 3);
  height: auto;
  aspect-ratio: 1/1;
  // border: 1px solid #e6e6e6;
  border-radius: 6px;
  box-sizing: border-box;
}

.scroller-grid-checkbox {
  position: absolute;
  top: 0;
  left: 6px;
}

.scroller-grid-close {
  position: absolute;
  top: 2px;
  right: 2px;
  background-color: rgba(0, 0, 0, 0.1);
  width: 20px;
  height: 20px;
  border-radius: 50%;
  display: flex;
  align-items: center;
}
</style>
